package cn.ms.light.core;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.netty.handler.codec.http.HttpMethod;
import io.reactivex.netty.channel.Handler;
import io.reactivex.netty.protocol.http.server.HttpServerRequest;
import io.reactivex.netty.protocol.http.server.HttpServerResponse;
import io.reactivex.netty.protocol.http.server.RequestHandler;
import jauter.Routed;
import rx.Observable;

public class Dispatch<I, O> implements RequestHandler<I, O> {

	private final Router<I, O> r;
	
	public HttpMethod[] httpMethods={HttpMethod.GET,HttpMethod.POST,HttpMethod.PUT,HttpMethod.DELETE,
			HttpMethod.HEAD,HttpMethod.CONNECT,HttpMethod.OPTIONS,HttpMethod.PATCH,HttpMethod.TRACE};
	
	private Dispatch(Router<I, O> r) {
		this.r = r;
	}

	/**
	 * DSL for creating an rxnetty-router
	 * 
	 * @param user supplied router
	 */
	public static <I, O> Dispatch<I, O> using(Router<I, O> r) {
		return new Dispatch<I, O>(r);
	}

	/**
	 * provides a lambda friendly API for defining a Route
	 * 
	 * @param route
	 */
	public static <I, O> Handler<HttpServerRequest<I>, HttpServerResponse<O>> withParams(Route<I, O> route) {
		return route;
	}

	@Override
	public Observable<Void> handle(HttpServerRequest<I> request, HttpServerResponse<O> response) {
		Routed<Handler<HttpServerRequest<I>, HttpServerResponse<O>>> routed = null;
		for (HttpMethod httpMethod:httpMethods) {
			routed = r.route(httpMethod, request.getPath());
			if(routed!=null){
				break;
			}
		}
		
		if (routed.target() instanceof Route) {
			Map<String, String> parameters= new HashMap<String, String>(); 
			Map<String, List<String>> queryParameters=request.getQueryParameters();
			if(queryParameters!=null){
				if(!queryParameters.isEmpty()){
					for (Map.Entry<String, List<String>> entry:queryParameters.entrySet()) {
						List<String> valus=entry.getValue();
						if(valus==null||valus.isEmpty()){
							continue;
						}
						if(valus.size()==1){
							parameters.put(entry.getKey(), entry.getValue().get(0));
						}
					}
				}
			}
			parameters.putAll(routed.params());
			
			return ((Route<I, O>) routed.target()).handle(parameters, request, response);
		} else{
			return routed.target().handle(request, response);
		}
	}
	
}
